<?php

namespace application\admin\controller;

use ticky\request;
use ticky\databack;

class database extends base {

    public $config;

    public function __construct() {
        parent::__construct();
        $this->config = array(
            'path' => RUNTIME_PATH . DIRECTORY_SEPARATOR . 'databack' . DIRECTORY_SEPARATOR, //备份文件目录
            'part' => 2097152, //2MB
            'compress' => 1, //是否压缩
            'level' => 4, //压缩水平
        );
    }

    /**
     * 数据库列表
     */
    public function index() {
        $ret = db()->query('SHOW TABLE STATUS');
        $this->assign('items', $ret);
        $this->display('database/index');
    }

    /**
     * 立即备份
     */
    public function backups() {
        if (isset($_POST['dosubmit'])) {
            $tables = request::get('tables', []);
            if (!$tables) {
                showmsg('请指定要备份的表!', '/admin/database');
            }
            $tables = is_array($tables) ? implode(',', $tables) : $tables;
            //备份目录不存在，先创建目录
            if (!is_dir($this->config['path'])) {
                @mkdir($this->config['path'], 0755, true);
                @file_put_contents($this->config['path'] . 'index.html', '');
            }
            //检查是否有正在执行的任务
            $lock = $this->config['path'] . 'backup.lock';
            if (is_file($lock)) {
                showmsg('检测到有一个备份任务正在执行，请稍后再试！');
            } else {
                $len = @file_put_contents($lock, SYS_TIME); //创建锁文件
            }
            if (!$len) {
                showmsg($this->config['path'] . '目录不存在或不可写，请检查！', 'stop');
            }
            session('backup_config', $this->config);
            //生成备份文件信息
            $file = array(
                'name' => random(6, 'abcdefghigklmzopqrstuvwxyz') . '-' . date('Ymd-His'),
                'part' => 1,
            );
            session('backup_file', $file);
            //缓存要备份的表
            session('backup_tables', request::get('tables', []));
            //创建备份文件
            $database = new databack($file, $this->config);
            if (false !== $database->create()) {
                showmsg('初始化成功！', '/admin/database/backups/?id=0&start=0', 1);
            } else {
                showmsg('初始化失败，备份文件创建失败！');
            }
        } elseif (isset($_GET['id']) && isset($_GET['start'])) {
            $tables = session('backup_tables');
            $id = intval($_GET['id']);
            $start = intval($_GET['start']);
            $database = new databack(session('backup_file'), session('backup_config'));
            $start = $database->backup($tables[$id], $start);
            if (false === $start) {  //出错
                showmsg('备份出错！');
            } elseif (0 === $start) { //下一表
                if (isset($tables[++$id])) {
                    showmsg('表' . $tables[$id] . '备份完成！', '/admin/database/backups/?id=' . $id . '&start=0', 0.1);
                } else {   //备份完成，清空缓存
                    @unlink(session('backup_config')['path'] . 'backup.lock');
                    session('backup_tables', null);
                    session('backup_file', null);
                    session('backup_config', null);
                    showmsg('备份全部完成！', '/admin/database/databacklist', 2);
                }
            } else {
                $rate = floor(100 * ($start[0] / $start[1]));
                showmsg('表' . $tables[$id] . '正在备份...(' . $rate . '%)', '/admin/database/backups/?id=' . $id . '&start=' . $start[0], 0.1);
            }
        } else {
            showmsg('参数错误！', '/admin/database');
        }
    }

    /**
     * 优化表
     */
    public function optimize() {
        $tables = request::get('tables', []);
        if (!$tables) {
            showmsg('请指定要优化的表!', '/admin/database');
        }
        $tables = is_array($tables) ? implode(',', $tables) : $tables;
        db()->query("OPTIMIZE TABLE $tables");
        showmsg('优化' . $tables . '表成功', '/admin/database');
    }

    /**
     * 修复表
     */
    public function repair() {
        $tables = request::get('tables', []);
        if (!$tables) {
            showmsg('请指定要修复的表!', '/admin/database');
        }
        $tables = is_array($tables) ? implode(',', $tables) : $tables;
        db()->query("REPAIR TABLE $tables");

        showmsg('修复' . $tables . '表成功', '/admin/database');
    }

    /**
     * 数据库备份列表
     */
    public function databacklist() {
        $data = array();
        $list = glob($this->config['path'] . '*');
        //debug($list);
        //[0] => E:\Luomg\Demo\TickyPHP2/\runtime\databack\664322-20190111-175409-1.sql.gz
        foreach ($list as $name) {
            //if (preg_match('/^[a-z]{6}-\d{8}-\d{6}-\d+\.sql(?:\.gz)?$/', basename($name))) {
            $info['filesize'] = sizecount(filesize($name));
            $info['filename'] = basename($name);
            $name = sscanf($info['filename'], '%6s-%4s%2s%2s-%2s%2s%2s-%d');
            $info['backtime'] = $name[1] . '-' . $name[2] . '-' . $name[3] . ' ' . $name[4] . ':' . $name[5] . ':' . $name[6];
            $info['random'] = $name[0];
            $info['part'] = $name[7];
            $info['time'] = strtotime($info['backtime']);
            $data[] = $info;
            //debug($data);
            //}
        }
        $this->assign('items', $data);

        $this->display('database/databacklist');
    }

    /**
     * 数据库备份文件删除
     */
    public function databackdel() {
        if (!isset($_GET['filename'])) {
            showmsg('请指定要下载的文件!');
        }
        $filename = $this->config['path'] . $_GET['filename'];
        if (!is_file($filename)) {
            showmsg($filename . '文件不存在!', 'stop');
        }
        array_map('unlink', glob($filename));
        if (count(glob($filename))) {
            showmsg('备份文件删除失败，请检查权限！');
        } else {
            showmsg('备份文件删除成功！', '', 1);
        }
    }

    /**
     * 数据库备份文件下载
     */
    public function databackdown() {
        if (!isset($_GET['filename'])) {
            showmsg('请指定要下载的文件!');
        }
        $filename = $_GET['filename'];
        if (!is_file($this->config['path'] . $filename)) {
            showmsg($filename . '文件不存在!', 'stop');
        }
        file_down($this->config['path'] . $filename);
    }

    /**
     * 数据库导入
     */
    public function import() {
        if (isset($_GET['time'])) {
            $filename = $_GET['random'] . '-' . date('Ymd-His', intval($_GET['time'])) . '-*.sql*';
            $path = $this->config['path'] . $filename;
            $files = glob($path);
            $list = array();
            foreach ($files as $name) {
                $basename = basename($name);
                $match = sscanf($basename, '%6s-%4s%2s%2s-%2s%2s%2s-%d');
                $gz = preg_match('/^[a-z]{6}-\d{8}-\d{6}-\d+\.sql.gz$/', $basename);
                $list[$match[7]] = array($match[7], $name, $gz);
            }
            ksort($list);
            //检测文件正确性
            $last = end($list);
            if (count($list) === $last[0]) {
                session('backup_list', $list);
                showmsg('初始化成功！', '/admin/database/import/?part=1&start=0', 1);
            } else {
                showmsg('备份文件可能已经损坏，请检查！');
            }
        } elseif (isset($_GET['part']) && isset($_GET['start'])) {
            $part = intval($_GET['part']);
            $start = intval($_GET['start']);
            $list = success('backup_list');
            if (!isset($list) || !is_array($list)) {
                showmsg('非法操作！');
            }
            $databack = new databack($list[$part], array('path' => $this->config['path'], 'compress' => $list[$part][2]));
            $start = $databack->import($start);
            if (false === $start) {
                showmsg('还原数据出错！');
            } elseif (0 === $start) { //下一卷
                if (isset($list[++$part])) {
                    showmsg('正在还原：卷' . $part . '...', '/admin/database/import/?part=' . $part . '&start=0', 1);
                } else {
                    success('backup_list', null);
                    showmsg('还原完成！', '/admin/database/databacklist', 2);
                }
            } else {
                if ($start[1]) {
                    $rate = floor(100 * ($start[0] / $start[1]));
                    showmsg('正在还原：卷' . $part . '...(' . $rate . '%)', '/admin/database/import/?part=' . $part . '&start=' . $start[0], 1);
                } else {
                    showmsg('正在还原：卷' . $part . '...', '/admin/database/import/?part=' . $part . '&start=' . $start[0] . '&gz=1', 1);
                }
            }
        } else {
            showmsg('参数错误！');
        }
    }

}
